package utilities;

import java.util.Hashtable;

import model.EdgeProgramGraph;
import model.EdgeTransitionSystem;
import model.ProgramGraph;
import model.TransitionSystem;
import model.VariableHashTable;

/** Class for creating the parallel composition of the example with the printing supervisor
 * @author DarkoLaptop2
 *
 */
public class ParallellComposition {

	/** Method for parallel composition of 5 graphs-without variables and creation of their parallel compositon ( a new graph with variable for every graph) 
	 * @param graphs - the graphs without variables
	 * @return a new graph with variables representing the parallel composition
	 */
	public static ProgramGraph parallellComposition(TransitionSystem[] graphs){
		Hashtable<String, Integer> graphLabelIndex=new Hashtable<String,Integer>();
		ProgramGraph parallell=new ProgramGraph();
		parallell.addNode(0, "00000");
		parallell.setInitialNode(0);
		VariableHashTable variableTable=new VariableHashTable();
		for(int i=0;i<graphs.length;i++) 
			variableTable.insertVariable(((char)('a'+i))+"",0);
			
		parallell.setInitialVariableValues(variableTable);
		graphLabelIndex.put("00000", 0);
		int sequence=1;
		for(int a=0;a<graphs[0].getAllNodes().size();a++)
			for(int b=0;b<graphs[1].getAllNodes().size();b++)
				for(int c=0;c<graphs[2].getAllNodes().size();c++)
					for(int d=0;d<graphs[3].getAllNodes().size();d++)
						for(int e=0;e<graphs[4].getAllNodes().size();e++){
							String fromStateLabel=graphs[0].getNodeName(a)+graphs[1].getNodeName(b)+graphs[2].getNodeName(c)+graphs[3].getNodeName(d)+graphs[4].getNodeName(e);
//							String fromStateLabel=a+""+b+""+c+""+d+""+e;
							if (!graphLabelIndex.containsKey(fromStateLabel)){
//								the resulting state doesn't exist
								//create a new state
								parallell.addNode(sequence++, fromStateLabel);
								graphLabelIndex.put(fromStateLabel, sequence-1);
							}
							int[] list={a,b,c,d,e};
							for(int i=0;i<list.length;i++){
								for(EdgeTransitionSystem transition:graphs[i].getNodeNeighbors(list[i])){
									//check the existing transitions in the fromStateLabel 
									boolean hasTransition=false;
									for(EdgeProgramGraph transitionParallell:parallell.getNodeNeighbors(graphLabelIndex.get(fromStateLabel))){
										if(transitionParallell.getTransitionName().equals(transition.getTransitionName())){
											//if there is a transition with same name 
											//code here
											String toStateLabel=transitionParallell.getToNode().getName();
											toStateLabel=getNewLabel(toStateLabel, i,transition.getToNode().getName());
											if (!graphLabelIndex.containsKey(toStateLabel)){
												//the resulting state doesn't exist
												//create a new state
												parallell.addNode(sequence++, toStateLabel);
												graphLabelIndex.put(toStateLabel, sequence-1);
											} 
											parallell.addEdge(graphLabelIndex.get(fromStateLabel), "(1==1)", transitionParallell.getActionString()+((char)('a'+i))+"="+transition.getToNode().getName()+";", transitionParallell.getTransitionName(), graphLabelIndex.get(toStateLabel));
											parallell.removeTransition(transitionParallell);
											hasTransition=true;
											break;
										} 
									}
									
									if(!hasTransition){
										//add a new transition
										String toStateLabel=fromStateLabel;
										toStateLabel=getNewLabel(toStateLabel, i,transition.getToNode().getName());
										if (!graphLabelIndex.containsKey(toStateLabel)){
											//the resulting state doesn't exist
											//create a new state
											parallell.addNode(sequence++, toStateLabel);
											graphLabelIndex.put(toStateLabel, sequence-1);
										} 
										
										parallell.addEdge(graphLabelIndex.get(fromStateLabel), "(1==1)", ((char)('a'+i))+"="+transition.getToNode().getName()+";", transition.getTransitionName(), graphLabelIndex.get(toStateLabel));
									}
								}
							}
						}
		for(int i=0;i<graphs.length;i++){
			for(String transitionName:graphs[i].getAllTransitions()){
				if(transitionName.charAt(0)=='_')
				parallell.setTransitionType(transitionName, false);
			}
		}
		for(int i=0;i<graphs.length;i++)
			parallell.addVariableDomain(((char)('a'+i))+"", 0, graphs[i].getAllNodes().size());
		return parallell;
	}
	
	/** Method for getting the new label of a given state name. A character on a given position must be replaced with a new given character
	 * @param label - the label of the state
	 * @param position - position of the character that will be replaced
	 * @param newChar - the new replacement character
	 * @return the new label
	 */
	public static String getNewLabel(String label,int position,String newChar){
		char[] newLabelC=label.toCharArray();
		newLabelC[position]=newChar.charAt(0);
		return String.valueOf(newLabelC);
	}

}
